package com.linciping.useges.plugin.util;

import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.file.PsiDirectoryFactory;
import com.intellij.psi.impl.file.PsiJavaDirectoryFactory;
import com.intellij.util.concurrency.AppExecutorUtil;
import com.linciping.useges.plugin.asyc.ProjectResUsegesForSourceCallable;
import com.linciping.useges.plugin.asyc.ResUsegesForSourceCallable;
import com.linciping.useges.plugin.bean.File2R;
import com.linciping.useges.plugin.bean.PsiFile2Content;
import com.linciping.useges.plugin.bean.Res2SourceFile;
import com.linciping.useges.plugin.bean.UsegesNode;
import org.jetbrains.jps.model.java.JavaResourceRootType;
import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
import org.jetbrains.kotlin.config.ResourceKotlinRootType;
import org.jetbrains.kotlin.psi.KtImportDirective;
import org.jetbrains.kotlin.psi.KtImportList;

import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

public class Util {

    private static final int SPLIT_SIZE = 50;
    private static final int MAX_POOL = 6;

    public static <T> List<List<T>> splitResFile(List<T> file2RList) {
        int size = file2RList.size();
        if (size <= SPLIT_SIZE) {
            return Collections.singletonList(file2RList);
        } else {
            int pool = size / SPLIT_SIZE;
            if (size % SPLIT_SIZE > 0) {
                pool++;
            }
            List<List<T>> resultList = new ArrayList<>(pool);
            if (pool <= MAX_POOL) {
                for (int i = 0; i < size; i += SPLIT_SIZE) {
                    int start = i;
                    int end = start + SPLIT_SIZE;
                    if (end > (size - 1)) {
                        end = size - 1;
                    }
                    resultList.add(file2RList.subList(start, end));
                }
            } else {
                int splitSize = size / MAX_POOL;
                for (int i = 0; i < MAX_POOL; i++) {
                    int start = i * splitSize;
                    int end;
                    if (i == (MAX_POOL - 1)) {
                        end = size - 1;
                    } else {
                        end = start + splitSize;
                    }
                    resultList.add(file2RList.subList(start, end));
                }
            }
            return resultList;
        }
    }

    public static List<Res2SourceFile> executorFind(final List<List<File2R>> file2RList, final List<PsiFile2Content> waitFindPsiFileContentList) throws ExecutionException, InterruptedException {
        return executorFind(file2RList, waitFindPsiFileContentList, true, null);
    }

    public static List<Res2SourceFile> executorFind(final List<List<File2R>> file2RList, final List<PsiFile2Content> waitFindPsiFileContentList, boolean isModule, String modulePackageName) throws ExecutionException, InterruptedException {
        int poolSize = file2RList.size();
        ExecutorService executor = AppExecutorUtil.getAppExecutorService();
        List<Callable<List<Res2SourceFile>>> callableList = new ArrayList<>(poolSize);
        for (List<File2R> file2RS : file2RList) {
            if (isModule) {
                callableList.add(new ResUsegesForSourceCallable(file2RS, waitFindPsiFileContentList));
            } else {
                callableList.add(new ProjectResUsegesForSourceCallable(file2RS, waitFindPsiFileContentList, modulePackageName));
            }
        }
        List<Res2SourceFile> res2SourceFileList = new ArrayList<>();
        List<Future<List<Res2SourceFile>>> futureList = executor.invokeAll(callableList);
        for (Future<List<Res2SourceFile>> innerFuture : futureList) {
            res2SourceFileList.addAll(innerFuture.get());
        }
        return res2SourceFileList;
    }

    public static boolean hasJavaImport(PsiImportList psiImportList, String packageName) {
        PsiImportStatement[] psiImportStatements = psiImportList.getImportStatements();
        if (psiImportStatements.length == 0) return false;
        for (PsiImportStatement psiImportStatement : psiImportStatements) {
            String importText = psiImportStatement.getText();
            if (importText.equals(packageName)) {
                return true;
            }
        }
        return false;
    }

    public static boolean hasKtImport(KtImportList ktImportList, String packageName) {
        List<KtImportDirective> ktImportDirectives = ktImportList.getImports();
        if (ktImportDirectives.size() == 0) return false;
        for (KtImportDirective ktImportDirective : ktImportDirectives) {
            String importText = ktImportDirective.getText();
            if (importText.equals(packageName)) {
                return true;
            }
        }
        return false;
    }

    public static boolean isPathEnd(String path, String end) {
        String[] pathItems = path.split("/");
        String pathEnd = pathItems[pathItems.length - 1];
        return pathEnd.equals(end);
    }

    public static boolean hasModule(AnActionEvent e) {
        Project project = e.getProject();
        if (project == null) {
            return false;
        }
        Module[] modules = ModuleManager.getInstance(project).getModules();
        return modules.length > 0;
    }

    public static boolean hasResDir(AnActionEvent e) {
        Project project = e.getProject();
        Module targetModule = e.getData(LangDataKeys.MODULE);
        if (project == null || targetModule == null) {
            return false;
        }
        Set<JpsModuleSourceRootType<?>> resourceRootTypes = new HashSet<>(2);
        resourceRootTypes.add(JavaResourceRootType.RESOURCE);
        resourceRootTypes.add(ResourceKotlinRootType.INSTANCE);
        List<VirtualFile> virtualFileList = ModuleRootManager.getInstance(targetModule).getSourceRoots(resourceRootTypes);
        return !virtualFileList.isEmpty();
    }
//
//    public static String getRootPackageName(Project project,UsegesNode rootNode,String packageName) {
//
//    }


    public static boolean isPackage(PsiNamedElement psiNamedElement, Project project) {
        if (psiNamedElement instanceof PsiDirectory) {
            return PsiJavaDirectoryFactory.getInstance(project).isPackage((PsiDirectory) psiNamedElement);
        }
        return false;
    }
}
